home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Magazin/MacEasy 12
/
Mac Magazin and MacEasy Magazine CD - Issue 12.iso
/
Sharewarebibliothek
/
Anwendungen
/
Wissenschaft & Technik
/
Yorick
/
yorick11-nofpu folder
/
include
/
plwf.i
< prev
next >
Wrap
Text File
|
1995-04-03
|
8KB
|
233 lines
/*
PLWF.I
Simple "painter's algorithm"-class routines for making 3-D wire frames.
$Id: plwf.i,v 1.1 1993/08/27 18:50:06 munro Exp $
*/
/* Copyright (c) 1994. The Regents of the University of California.
All rights reserved. */
func plwf(z,y,x, fill=,edges=,ecolor=,ewidth=,cull=,scale=)
/* DOCUMENT plwf, z
or plwf, z, y,x
plots a 3-D wire frame of the given Z array, which must have the
same dimensions as the mesh (X, Y). The orientation of the
model can be set using the plwfset routine. For most photogenic
results, use style="nobox.gs" in the window command, since the
projected axis ticks and labels are not very useful.
The drawing order of the zones is determined by a simple "painter's
algorithm", which works fairly well if the mesh is reasonably near
rectilinear, but can fail even then if the viewpoint is chosen to
produce extreme fisheye perspective effects. Look at the resulting
plot carefully to be sure the algorthm has correctly rendered the
model in each case.
The viewpoint and default mesh can be set using the plwfset command.
KEYWORDS: fill -- optional colors to use (default is to make zones
have background color), same dimension options as
for z argument to plf function
edges -- default is 1 (draw edges), but if you provide fill
colors, you may set to 0 to supress the edges
ecolor, ewidth -- color and width of edges
cull -- default is 1 (cull back surfaces), but if you want
to see the "underside" of the model, set to 0
scale -- by default, Z is scaled to "reasonable" maximum
and minimum values related to the scale of (X,Y).
This keyword alters the default scaling factor, in
the sense that scale=2.0 will produce twice the
Z-relief of the default scale=1.0.
SEE ALSO: plm, plf, plwfset
*/
{
extern _plwf_y, _plwf_x, _plwf_z, _plwf_order;
extern _plwf_theta, _plwf_phi, _plwf_psi, _plwf_vf;
_plwf_mesh, y, x;
/* flip z and fill into drawing order */
if (_plwf_order&1) zs= transpose(z);
else zs= z;
if (_plwf_order&2) zs= zs(::-1,);
if (_plwf_order&4) zs= zs(,::-1);
if (!is_void(fill)) {
if (_plwf_order&1) fill= transpose(fill);
if (_plwf_order&2) fill= fill(::-1,);
if (_plwf_order&4) fill= fill(,::-1);
}
zs-= avg(zs); /* center z at 0 */
zmax= max(zs);
sint= sin(_plwf_theta);
if (zmax && sint) {
zs/= zmax*sqrt(3)*sint; /* guess at reasonable scale */
if (!is_void(scale)) zs*= scale;
}
xs= _plwf_x + zs*sint*cos(_plwf_phi);
ys= _plwf_y + zs*sint*sin(_plwf_phi);
zs= _plwf_z + zs*cos(_plwf_theta);
/* (xs,ys) guaranteed to be centered at (0,0) by construction --
compute viewing distance and do perspective projection */
/* This is not really the advertised definition of viewfield,
but the real thing is very difficult to compute... */
z0= max(zs) + max(max(xs),max(ys))/_plwf_vf;
z0-= zs; /* guaranteed positive */
xs/= z0;
ys/= z0;
/* scale to fit into plsys,0 (NDC coordinates) */
extern _plwf_xmin, _plwf_xmax, _plwf_ymin, _plwf_ymax;
xmax= max(xs);
xmin= min(xs);
ymax= max(ys);
ymin= min(ys);
s= (_plwf_xmax-_plwf_xmin)/(xmax-xmin);
sy= (_plwf_ymax-_plwf_ymin)/(ymax-ymin);
if (s<sy) {
ox= _plwf_xmin-s*xmin;
oy= 0.5*((_plwf_ymax+_plwf_ymin)-s*(ymin+ymax));
} else {
s= sy;
oy= _plwf_ymin-s*ymin;
ox= 0.5*((_plwf_xmax+_plwf_xmin)-s*(xmin+xmax));
}
xs= s*xs+ox;
ys= s*ys+oy;
if (is_void(edges)) edges= 1;
plf, fill, ys,xs, edges=edges,ecolor=ecolor,ewidth=ewidth;
}
/* The default screen coordinates (plsys, 0) run from (.1137,.3683)
to (.6764,.9292). If you use a landscape style, you will want
to use different coordinates. Or use window, style="nobox.gs". */
_plwf_xmin= 0.399-0.2;
_plwf_xmax= 0.399+0.2;
_plwf_ymin= 0.634-0.2;
_plwf_ymax= 0.634+0.2;
func plwfset(y,x, theta=,phi=,psi=, viewfield=)
/* DOCUMENT plwfset, <keyword_args>
or plwfset, y,x <keyword_args>
sets the viewing angle and perspective and/or the default mesh for
the plwf command.
THETA, PHI, and PSI are Euler angles for the projection of the
model (x, y, scale*z) onto the (xs,ys) plane of the screen.
Imagine that (x,y) initially coincide with (xs,ys), with xs to
the right, ys upward, and zs out of the screen towards you. Then
rotate the model by THETA radians about the ys-axis, so that
positive THETA would advance a right-hand screw upward (to +ys).
Next, rotate the tilted model PHI radians about the zs-axis, so
that positive PHI advances a right-hand screw towards you (to +zs).
Finally, rotate the model PSI radians about its own z-axis, again
in a right-hand sense. The default values are THETA=acos(1/sqrt(3)),
PHI=pi/2, and PSI=pi/4, which plots Z vertically, X 30 degrees down
to the right, and y 30 degrees up to the right. Note that PHI=pi/2
will make Z increase upwards for all sensible values of THETA.
The VIEWFIELD is the angle in radians from the center of the model
to the point which is farthest from the center, as seen from the
perspective of the viewpoint. Small VIEWFIELD means you are looking
at the model through a telescope from a great distance; VIEWFIELD
near pi/2 is an extreme "fisheye" perspective.
SEE ALSO: plwf
*/
{
extern _plwf_y_d, _plwf_x_d, _plwf_z_d, _plwf_order_d;
extern _plwf_y, _plwf_x, _plwf_z, _plwf_order;
extern _plwf_theta, _plwf_phi, _plwf_psi, _plwf_vf;
if (!is_void(theta)) _plwf_theta= theta;
if (!is_void(phi)) _plwf_phi= phi;
if (!is_void(psi)) _plwf_psi= psi;
if (!is_void(viewfield)) {
if (viewfield<atan(0.0625)) _plwf_vf= 0.0625;
else if (viewfield>atan(12.5)) _plwf_vf= 12.5;
else _plwf_vf= tan(viewfield);
}
/* The mesh must be set AFTER the viewing direction to allow _plwf_mesh
to properly compute the order. */
if (!is_void(y)) {
_plwf_mesh(y, x);
_plwf_y_d= _plwf_y;
_plwf_x_d= _plwf_x;
_plwf_z_d= _plwf_z;
_plwf_order_d= _plwf_order;
}
}
_plwf_theta= acos(1./sqrt(3.));
_plwf_phi= 0.5*pi;
_plwf_psi= 0.25*pi;
_plwf_vf= 0.5;
func _plwf_mesh(y, x)
{
extern _plwf_y_d, _plwf_x_d, _plwf_z_d, _plwf_order_d;
extern _plwf_y, _plwf_x, _plwf_z, _plwf_order;
if (is_void(y)) {
_plwf_y= _plwf_y_d;
_plwf_x= _plwf_x_d;
_plwf_z= _plwf_z_d;
_plwf_order= _plwf_order_d;
return;
}
/* The order either requires a transpose or not, reversal of the
order of the first dimension or not, and reversal of the order
of the second dimension or not. */
/* rotate (x,y,0) into on-screen orientation to determine order */
xs2= x*cos(_plwf_psi)-y*sin(_plwf_psi);
_plwf_y= y*cos(_plwf_psi)+x*sin(_plwf_psi);
_plwf_z= -xs2*sin(_plwf_theta);
xs2*= cos(_plwf_theta);
_plwf_x= xs2*cos(_plwf_phi)-_plwf_y*sin(_plwf_phi);
_plwf_y= _plwf_y*cos(_plwf_phi)+xs2*sin(_plwf_phi);
/* compute mean i-edge and j-edge vector z-components */
iedge= avg(_plwf_z(dif,));
jedge= avg(_plwf_z(,dif));
/* The direction with the minimum magnitude average z-component must
vary fastest in the painting order. If this is the j-direction,
a transpose will be required to make this the i-direction. */
if (_plwf_order= abs(jedge)<abs(iedge)? 1 : 0) {
tmp= iedge; iedge= jedge; jedge= tmp;
_plwf_x= transpose(_plwf_x);
_plwf_y= transpose(_plwf_y);
_plwf_z= transpose(_plwf_z);
}
/* Zones must be drawn from back to front, which means that the
average z-component of the edge vectors must be positive. This
can be arranged by reversing the order of the elements if
necessary. */
if (iedge<0.0) {
_plwf_order|= 2;
_plwf_x= _plwf_x(::-1,);
_plwf_y= _plwf_y(::-1,);
_plwf_z= _plwf_z(::-1,);
}
if (jedge<0.0) {
_plwf_order|= 4;
_plwf_x= _plwf_x(,::-1);
_plwf_y= _plwf_y(,::-1);
_plwf_z= _plwf_z(,::-1);
}
/* put center of mesh at (0,0) in screen coordinates */
_plwf_x-= avg(_plwf_x);
_plwf_y-= avg(_plwf_y);
_plwf_z-= avg(_plwf_z);
/* normalize mesh so that biggest dimension is 1.0 */
xmax= max(_plwf_x);
ymax= max(_plwf_y);
if (ymax>xmax) xmax= ymax;
_plwf_x/= xmax;
_plwf_y/= xmax;
_plwf_z/= xmax;
}